#ifndef LAURIN_IEEE80211_H_
#define LAURIN_IEEE80211_H_

#include "laurin-utils.h" // for ETH_ALEN
#include <sys/types.h>


// some code is from ieee80211.h
// copyrights holds.
// code is repeated for not assuming a specific kernel configuration.

/*
 802.11 data frame from AP

      ,-------------------------------------------------------------------.
Bytes |  2   |  2   |    6    |    6    |    6    |  2   | 0..2312 |   4  |
      |------|------|---------|---------|---------|------|---------|------|
Desc. | ctrl | dura |  DA/RA  |   TA    |    SA   | Sequ |  frame  |  fcs |
      |      | tion | (BSSID) |         |         | ence |  data   |      |
      `-------------------------------------------------------------------'

Total: 28-2340 bytes

*/

/* Frame control field constants */
#define IEEE80211_FCTL_VERS             0x0003          /* version */
#define IEEE80211_FCTL_FTYPE            0x000c          /* type */
#define IEEE80211_FCTL_STYPE            0x00f0          /* subtype */
#define IEEE80211_FCTL_TODS             0x0100          /* to ds */
#define IEEE80211_FCTL_FROMDS           0x0200          /* from ds */
#define IEEE80211_FCTL_MOREFRAGS        0x0400          /* more fragments remains?*/
#define IEEE80211_FCTL_RETRY            0x0800          /* retry */
#define IEEE80211_FCTL_PM               0x1000          /* power management */
#define IEEE80211_FCTL_MOREDATA         0x2000          /* AP has more buffered frame for STA */
#define IEEE80211_FCTL_PROTECTED        0x4000          /* crypted? */
#define IEEE80211_FCTL_ORDER            0x8000          /* sta requires frames to be delivered in order */

/* frame type */
#define IEEE80211_FTYPE_MGMT            0x0000          /* management frame */
#define IEEE80211_FTYPE_CTL             0x0004          /* control frame */
#define IEEE80211_FTYPE_DATA            0x0008          /* data frame */

/* management subtype */
#define IEEE80211_STYPE_ASSOC_REQ       0x0000          /* association request */
#define IEEE80211_STYPE_ASSOC_RESP      0x0010          /* association response */
#define IEEE80211_STYPE_REASSOC_REQ     0x0020          /* reassociation request */
#define IEEE80211_STYPE_REASSOC_RESP    0x0030          /* reassociation response */
#define IEEE80211_STYPE_PROBE_REQ       0x0040          /* probe request */
#define IEEE80211_STYPE_PROBE_RESP      0x0050          /* probe response */
#define IEEE80211_STYPE_BEACON          0x0080          /* beacon */
#define IEEE80211_STYPE_ATIM            0x0090          /* announcement traffic indication map (ATIM) */
#define IEEE80211_STYPE_DISASSOC        0x00A0          /* disassociate */
#define IEEE80211_STYPE_AUTH            0x00B0          /* authentication */
#define IEEE80211_STYPE_DEAUTH          0x00C0          /* deauthentication */
#define IEEE80211_STYPE_ACTION          0x00D0          /* action frame */

/* control subtype */
#define IEEE80211_STYPE_PSPOLL          0x00A0          /* power-save poll */
#define IEEE80211_STYPE_RTS             0x00B0          /* request to send*/
#define IEEE80211_STYPE_CTS             0x00C0          /* clear to send */
#define IEEE80211_STYPE_ACK             0x00D0          /* ack */
#define IEEE80211_STYPE_CFEND           0x00E0          /* content free period end */
#define IEEE80211_STYPE_CFENDACK        0x00F0          /* content free period end ack */

/* data subtype */
#define IEEE80211_STYPE_DATA            0x0000          /* data */
#define IEEE80211_STYPE_DATA_CFACK      0x0010          /* data + content free ack */
#define IEEE80211_STYPE_DATA_CFPOLL     0x0020          /* data + content free poll */
#define IEEE80211_STYPE_DATA_CFACKPOLL  0x0030          /* data + content free ack + content free poll */
#define IEEE80211_STYPE_NULLFUNC        0x0040          /* null data */
#define IEEE80211_STYPE_CFACK           0x0050          /* content free ack */
#define IEEE80211_STYPE_CFPOLL          0x0060          /* content free poll */
#define IEEE80211_STYPE_CFACKPOLL       0x0070          /* content free ack + poll */
#define IEEE80211_STYPE_QOS_DATA        0x0080          /* qos data */


#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS)               /* get protocol version - always 0*/
#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)              /* get frame type */
#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)             /* get frame subtype */
#define WLAN_FC_GET_FROMDS(fc) ((fc) & IEEE80211_FCTL_FROMDS)   		 /* get from ds bit value */
#define WLAN_FC_GET_TODS(fc) ((fc) & IEEE80211_FCTL_TODS)               /* get to ds bit value */


#define IEEE80211_1ADDR_LEN 10
#define IEEE80211_3ADDR_LEN 24
#define IEEE80211_TAGGED_PARAMETERS_OFFSET 36



// from this we can get the right header checking the frame_ctl fields.
struct laurin_ieee80211_hdr {
        u_int16_t frame_ctl;
        u_int16_t duration_id;
        u_int8_t payload[0];
} __attribute__((packed));


struct laurin_ieee80211_hdr_1addr {
        u_int16_t frame_ctl;
        u_int16_t duration_id;
        u_int8_t addr1[ETH_ALEN];
        u_int8_t payload[0];
} __attribute__ ((packed));


struct laurin_ieee80211_hdr_3addr {
        u_int16_t frame_ctl;
        u_int16_t duration_id;
        u_int8_t addr1[ETH_ALEN];
        u_int8_t addr2[ETH_ALEN];
        u_int8_t addr3[ETH_ALEN];
        u_int16_t seq_ctl;
        u_int8_t payload[0];
} __attribute__((packed));


#endif
